<?php


namespace app\common\controller;

use app\api\model\Admin;
use app\api\model\AdminRole;
use think\Controller;
use think\Db;
use think\exception\HttpResponseException;
use think\Request;
use think\Response;

/**
 * Api控制器基类
 * Class Api
 * @package app\common\controller
 */
class Api extends Controller
{
    /**
     * @var bool 无需登录的方法
     */
    protected $noNeedLogin = [];

    /**
     * @var bool 无需鉴权的方法
     */
    protected $noNeedAuth = [];

    /**
     * @var array 无需token的方法
     */
    protected $noNeedToken = [];

    /**
     * @var array 前置方法名
     */
    protected $beforeActionList = [
        'checkApiSafety' => ['check_auth'],   // 校验api接口安全性
    ];

    protected function _initialize()
    {
        $this->beforeActionList['check_auth'] = [
            ['except' => "'" . implode(",", $this->noNeedAuth) . "'"]
        ];
    }

    /**
     * 操作成功返回的数据
     * @param string $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为1
     * @param string $type 输出类型
     * @param array $header 发送的 Header 信息
     */
    public function success($msg = '', $data = null, $code = 1, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 操作失败返回的数据
     * @param string $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为0
     * @param string $type 输出类型
     * @param array $header 发送的 Header 信息
     */
    public function error($msg = '', $data = null, $code = 0, $type = null, array $header = [])
    {
        $this->result($msg, $data, $code, $type, $header);
    }

    /**
     * 返回封装后的 API 数据到客户端
     * @access public
     * @param mixed $msg 提示信息
     * @param mixed $data 要返回的数据
     * @param int $code 错误码，默认为0
     * @param string $type 输出类型，支持json/xml/jsonp
     * @param array $header 发送的 Header 信息
     * @return void
     * @throws HttpResponseException
     */
    public function result($msg, $data = null, $code = 0, $type = null, array $header = [])
    {
        $result = [
            'code' => $code,
            'msg' => $msg,
            'time' => Request::instance()->server('REQUEST_TIME'),
            'data' => $data,
        ];
        // 如果未设置类型则自动判断
        $type = $type ? $type : 'json';

        if (isset($header['statuscode'])) {
            $code = $header['statuscode'];
            unset($header['statuscode']);
        } else {
            //未设置状态码,根据code值判断
            $code = $code >= 1000 || $code < 200 ? 200 : $code;
        }
        $response = Response::create($result, $type, $code)->header($header);
        throw new HttpResponseException($response);
    }

    /**
     * 校验签名
     */
    private function checkSign()
    {

    }

    /**
     * 校验token
     * @param string $token 用户token
     */
    private function checkToken(string $token)
    {
        $UserTokenExpireTime = (new \app\api\model\AdminToken)->where('token', $token)->value('expire_time');
        empty($UserTokenExpireTime) && self::error('error', ['data' => '非法登录'], 202);
        time() > $UserTokenExpireTime && self::error('error', ['data' => '用户token超时'], 202);
    }

    /**
     * 校验API安全性
     * @throws \HttpResponseException
     */
    protected function checkApiSafety()
    {
        // 跨域检测
        check_cors_request();
        // 获取token
        $token = Request::instance()->header('token') ?? '';
        // 当前请求方法名
        $currentName = strtolower($this->request->action());
        // 当前控制器无需登录的方法
        $noNeedLogin = $this->noNeedLogin;
        // 判断当前方法是需要登录
        if (!in_array($currentName, $noNeedLogin)) {
            $this->checkToken($token);
        }
    }

    /**
     * 生成密码和加密盐
     * @param string $password 密码
     * @return array
     */
    public static function generatePassword(string $password): array
    {
        // 获取加密盐
        $salt = Util::random(6, 'string');
        // 生成加密后的密码
        $encryptPassword = md5(md5($password) . $salt);
        // 返回密码和密码盐
        return array(
            'encryptPassword' => $encryptPassword,
            'salt' => $salt
        );
    }

    /**
     * 加密
     * @param string $password 密码
     * @param string $salt 密码盐
     * @return string
     */
    public static function decryptPassword(string $password, string $salt): string
    {
        return md5($password . $salt);
    }

    /**
     * 递归生成子菜单
     * @param $pid
     * @param $menuList
     * @return array
     */
    public static function build_menu_child($pid, $menuList): array
    {
        $treeList = [];
        foreach ($menuList as $v) {
            if ($pid == $v['pid']) {
                $node = $v;
                $child = self::build_menu_child($v['id'], $menuList);
                if (!empty($child)) {
                    $node['child'] = $child;
                } else {
                    $node['child'] = [];
                }
                // todo 后续在此进行权限判断
                $treeList[] = $node;
            }
        }
        return $treeList;
    }

    /**
     * 构造查询参数
     * @param array $where
     * @return array
     */
    public static function build_params($where = []): array
    {
        $queryWhere = [];
        foreach ($where as $k => $v) {
            if ($where[$k] == '') {
                if (strpos($k, 'time')) {
                    $queryWhere[$k] = ['between', [time(), time()]];
                } else {
                    $queryWhere[$k] = [['like', '%' . $v . '%'], ['null', ''], 'or'];
                }
            } else {
                if (strpos($k, 'time')) {
                    $timeArr = explode(',', $v);
                    $queryWhere[$k] = ['between', [
                        (!isset($timeArr[0]) || empty($timeArr[0])) ? time() : $timeArr[0],
                        (!isset($timeArr[1]) || empty($timeArr[1])) ? time() : $timeArr[1]
                    ]];
                } else {
                    $queryWhere[$k] = ['like', '%' . $v . '%'];
                }
            }
        }
        return $queryWhere;
    }

    /**
     * 鉴权
     */
    public function check_auth()
    {
        // controller名
        $currentControllerName = strtolower($this->request->controller());
        // 方法名
        $actionName = strtolower($this->request->action());
        // 权限信息
        $authInfo = $currentControllerName . '/' . $actionName;
        // 根据token获取用户
        $token = Request::instance()->header('token') ?? [];
        if (!in_array($actionName, $this->noNeedAuth)) {
            $admin = Admin::get(['token' => $token]);
            if (empty($admin)) {
                $this->error('error', '不存在该用户!', 201);
            } else {
                // 当前方法名所对应的权限表示的id
                $authId = Db::name('system_menu')
                    ->where('perms', '=', $authInfo)
                    ->column('id');
                if ($admin['root'] === 1) {
                    return true;
                } else {
                    // 判断当前用户是否拥有此权限
                    $adminRoleId = AdminRole::get(['admin_id' => $admin['id']]);
                    $findRoleExist = Db::name('system_role_menu')
                        ->where('role_id', '=', $adminRoleId['role_id'])
                        ->where('menu_id', 'in', $authId)
                        ->select();
                    if (empty($findRoleExist)) {
                        $this->error('error', '当前用户无访问权限!', 403);
                    } else {
                        return true;
                    }
                }
            }
        }
    }
}